package com.kuaidao.sys.util;

import java.io.*;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * MyBatis代码生成
 */

public class CodeGen {

    /**
     * ip
     **/
    private static final String ip = "127.0.0.1";
    /**
     * 端口
     **/
    private static final String port = "3306";
    /**
     * 用户名
     **/
    private static final String user = "root";
    /**
     * 密码
     **/
    private static final String password = "123456";
    /**
     * 数据库
     **/
    private static final String db = "sys_center";
    /**
     * 方法 注释
     **/
    private final static String METHOD_NOTES = "\t\r/**\r\n  \t * %s\r\n \t * @param:%s\r\n\r\r\t */\r\n";
    /**
     * 类 注释
     **/
    private final static String CLASS_NOTES = "\r\n/**\r\n *\r\n * @Author " + System.getProperty("user.name") + "\r\n * @since 1.0.0\r\n */\r\n\n";

    public static void main(String[] args) throws IOException {
        long start = System.currentTimeMillis();
        // 导出文件的路径
        String outputBasePath = "D:/other/code/";
        // 服务名
        String serviceId = "sys";
        // 文件包名
        String packageName = "dictionary";
        // entity所在包名
        String entityPackageName = "com.kuaidao." + serviceId + ".entity" + "." + packageName;
        // daoMapper所在包名
        String daoMapperPackageName = "com.kuaidao." + serviceId + ".mapper" + "." + packageName;
        // 数据库表名，多个逗号分隔
        String tableNames = "t_dictionary_edition";
        String[] array = tableNames.split(",");
        for (String tableName : array) {
            // build model name
            String modelName = "";
            String[] tableNameWords = tableName.toLowerCase().split("_");
            StringBuffer sb = new StringBuffer();
            for (int i = 0; i < tableNameWords.length; i++) {
                if ("t".equals(tableNameWords[i]) && i == 0) {
                    continue;
                }
                sb.append(tableNameWords[i].substring(0, 1).toUpperCase() + tableNameWords[i].substring(1));
            }
            modelName = sb.toString();
            // get columns
            Map<String, Object> map = getDbInfo(tableName);
            List<JavaColumn> javaList = (List<JavaColumn>) map.get("javaList");
            List<DbColumn> dbList = (List<DbColumn>) map.get("dbList");
            // output po file
            List<String> poLines = writePo(entityPackageName, modelName, javaList);
            outputFile(outputBasePath + serviceId + "/entity/" + modelName + ".java", poLines);
            // output mapperdao
            List<String> daoLines = writeDao(daoMapperPackageName, entityPackageName, modelName);
            outputFile(outputBasePath + serviceId + "/daoMapper/" + modelName + "Mapper.java", daoLines);
            // output mapper
            List<String> mapperLines = writeMapper(tableName, modelName, daoMapperPackageName, entityPackageName, dbList, javaList);
            outputFile(outputBasePath + serviceId + "/resourceMapper/" + modelName + "Mapper.xml", mapperLines);
        }
        System.out.println("生成文件完成，共花费:" + (System.currentTimeMillis() - start));

    }

    public static Map<String, Object> getDbInfo(String tableName) {
        Map<String, Object> map = new HashMap<String, Object>();
        List<JavaColumn> javaList = new ArrayList<JavaColumn>();
        List<DbColumn> dbList = new ArrayList<DbColumn>();
        String url = "jdbc:mysql://" + ip + ":" + port + "/" + db + "?user=" + user + "&password=" + password
                + "&useUnicode=true&characterEncoding=UTF8&serverTimezone=Asia/Shanghai";
        Connection conn = null;
        String sql = "select column_name, data_type ,column_comment from information_schema.columns t where table_name='" + tableName
                + "' and table_schema = '" + db + "'";
        try {
            Class.forName("com.mysql.cj.jdbc.Driver");
            conn = DriverManager.getConnection(url);
            Statement stmt = conn.createStatement();
            ResultSet rs = stmt.executeQuery(sql);
            while (rs.next()) {
                String columnName = rs.getString("column_name");
                String dataType = rs.getString("data_type");
                String remark = rs.getString("column_comment");
                javaList.add(new JavaColumn(columnName, dataType, remark));
                dbList.add(new DbColumn(columnName, dataType, remark));
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        map.put("javaList", javaList);
        map.put("dbList", dbList);

        return map;
    }

    public static List<String> writePo(String entityPackageName, String fileName, List<JavaColumn> columns) {
        List<String> fileLines = new ArrayList<String>();
        fileLines.add("package " + entityPackageName + ";\n\n");
        fileLines.add("import java.util.Date;\n\n");
        fileLines.add("import lombok.Data;\n\n");
        fileLines.add(CLASS_NOTES);
        fileLines.add("@Data \n");
        fileLines.add("public class " + fileName + "{\n\n");
        if (columns != null && columns.size() > 0) {
            // create fields
            for (JavaColumn c : columns) {
                fileLines.add("\t/**" + c.getRemark() + "**/ \r\n");
                fileLines.add("\tprivate " + c.getType() + " " + c.getName() + ";\n\n");
            }
        }

        fileLines.add("}");
        return fileLines;
    }

    public static List<String> writeDao(String daoMapperPackageName, String entityPackageName, String modelName) {
        List<String> fileLines = new ArrayList<String>();
        fileLines.add("package " + daoMapperPackageName + ";\n\n");
        fileLines.add("import " + entityPackageName + "." + modelName + ";\n\n");
        fileLines.add("import java.util.List;\n\n");
        fileLines.add("import java.util.Map;\n\n");
        fileLines.add("import com.kuaidao.common.mapper.IBaseCRUD;\n\n");
        fileLines.add(CLASS_NOTES);
        fileLines.add("public interface " + modelName + "Mapper" + "  extends IBaseCRUD<" + modelName + ", Long> {\n\n");
        String fileNameVar = modelName.substring(0, 1).toLowerCase() + modelName.substring(1);
        // add
        fileLines.add(String.format(METHOD_NOTES, "新增", fileNameVar));
        fileLines.add("\t@Override \n");
        fileLines.add("\tboolean insert(" + modelName + " entity);\n\n");
        // update
        fileLines.add(String.format(METHOD_NOTES, "更新", fileNameVar));
        fileLines.add("\t@Override \n");
        fileLines.add("\tboolean update(" + modelName + " entity);\n\n");
        // delete
        fileLines.add(String.format(METHOD_NOTES, "删除（根据主键ID删除", "PrimaryKey"));
        fileLines.add("\t@Override \n");
        fileLines.add("\tboolean deleteByPrimaryKey(Long primaryKey);\n\n");
        // delete batch
        fileLines.add(String.format(METHOD_NOTES, "批量删除", "keys"));
        fileLines.add("\t@Override \n");
        fileLines.add("\t boolean deleteBatchByPrimaryKeyList(List<Long> keys);\n\n");
        // get
        fileLines.add(String.format(METHOD_NOTES, "根据主键查询", "PrimaryKey"));
        fileLines.add("\t@Override \n");
        fileLines.add("\t" + modelName + " findByPrimaryKey(Long primaryKey);\n\n");
        // List
        fileLines.add(String.format(METHOD_NOTES, "按条件查询", "paramMap"));
        fileLines.add("\t@Override \n");
        fileLines.add("\tList<" + modelName + "> findEntityListByParams(Map<String, Object> paramMap);\n\n");
        fileLines.add("}");
        return fileLines;
    }

    public static List<String> writeMapper(String tableName, String modelName, String daoMapperPackageName, String entityPackageName,
                                           List<DbColumn> dbList, List<JavaColumn> javaList) {
        List<String> fileLines = new ArrayList<String>();
        fileLines.add("<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n");
        fileLines.add("<!DOCTYPE mapper PUBLIC \"-//mybatis.org//DTD Mapper 3.0//EN\" \"http://mybatis.org/dtd/mybatis-3-mapper.dtd\">\n");
        fileLines.add("<mapper namespace=\"" + daoMapperPackageName + "." + modelName + "Mapper\">\n\n");

        // resultMap
        fileLines.add("\t<resultMap id=\"baseResultMap\" type=\"" + entityPackageName + "." + modelName + "\">\n");
        for (int i = 0; i < dbList.size(); i++) {
            DbColumn dc = dbList.get(i);
            JavaColumn jc = javaList.get(i);
            fileLines.add("\t\t<result column=\"" + dc.getName() + "\" property=\"" + jc.getName() + "\" />\n");
        }
        fileLines.add("\t</resultMap>\n\n");

        // columns
        fileLines.add("\t<sql id=\"columns\">\n");
        for (int i = 0; i < dbList.size(); i++) {
            DbColumn dc = dbList.get(i);
            if (i == 0) {
                fileLines.add("\t\t");
            }
            fileLines.add(dc.getName());
            if (i == dbList.size() - 1) {
                fileLines.add("\n");
            } else {
                fileLines.add(", ");
            }
        }
        fileLines.add("\t</sql>\n\n");

        // wheres
        fileLines.add("\t<sql id=\"wheres\">\n");
        fileLines.add("\t\twhere 1 = 1\n");
        for (int i = 0; i < dbList.size(); i++) {
            DbColumn dc = dbList.get(i);
            JavaColumn jc = javaList.get(i);
            if ("String".equals(jc.getType())) {
                fileLines.add("\t\t<if test=\"" + jc.getName() + " != null and " + jc.getName() + " != ''\">\n");
            } else {
                fileLines.add("\t\t<if test=\"" + jc.getName() + " != null\">\n");
            }
            fileLines.add("\t\t\tand " + dc.getName() + " = #{" + jc.getName() + "} \n");
            fileLines.add("\t\t</if>\n");
        }
        fileLines.add("\t</sql>\n\n");
        // get
        fileLines.add("\t<select id=\"findByPrimaryKey\"  resultMap=\"baseResultMap\">\n");
        fileLines.add("\t\tselect\n\t\t\t<include refid=\"columns\" />\n\t\tfrom " + tableName + "\n\t\twhere id = #{id}\n\t\tlimit 1\n");
        fileLines.add("\t</select>\n\n");

        // list
        fileLines.add("\t<select id=\"findEntityListByParams\"   resultMap=\"baseResultMap\">\n");
        fileLines.add("\t\tselect\n\t\t\t<include refid=\"columns\" />\n\t\tfrom " + tableName + "\n\t\t<include refid=\"wheres\" />\n");
        fileLines.add("\t</select>\n\n");

        // insert
        fileLines.add("\t<insert id=\"insert\" useGeneratedKeys=\"true\" keyProperty=\"id\">\n");
        fileLines.add("\t\tinsert into " + tableName + " \n");
        fileLines.add("\t\t<trim prefix=\"(\" suffix=\")\" suffixOverrides=\",\" >\n");
        for (int i = 0; i < dbList.size(); i++) {
            DbColumn dc = dbList.get(i);
            JavaColumn jc = javaList.get(i);
            if ("String".equals(jc.getType())) {
                fileLines.add("\t\t\t<if test=\"" + jc.getName() + " != null and " + jc.getName() + " != ''\">\n");
            } else {
                fileLines.add("\t\t\t<if test=\"" + jc.getName() + " != null\">\n");
            }
            fileLines.add("\t\t\t\t" + dc.getName());
            fileLines.add(",\n");
            fileLines.add("\t\t\t</if>\n");
        }
        fileLines.add("\t\t</trim>\n");
        fileLines.add("\t\t<trim prefix=\"values (\" suffix=\")\" suffixOverrides=\",\" >\n");
        for (int i = 0; i < javaList.size(); i++) {
            JavaColumn jc = javaList.get(i);
            if ("String".equals(jc.getType())) {
                fileLines.add("\t\t\t<if test=\"" + jc.getName() + " != null and " + jc.getName() + " != ''\">\n");
            } else {
                fileLines.add("\t\t\t<if test=\"" + jc.getName() + " != null\">\n");
            }
            fileLines.add("\t\t\t\t#{" + jc.getName() + "}");
            fileLines.add(",\n");
            fileLines.add("\t\t\t</if>\n");
        }
        fileLines.add("\t\t</trim>\n");
        fileLines.add("\t</insert>\n\n");

        // update
        fileLines.add("\t<update id=\"update\">\n");
        fileLines.add("\t\tupdate " + tableName + "\n");
        fileLines.add("\t\t<set>\n");
        for (int i = 0; i < dbList.size(); i++) {
            DbColumn dc = dbList.get(i);
            JavaColumn jc = javaList.get(i);
            if ("String".equals(jc.getType())) {
                fileLines.add("\t\t\t<if test=\"" + jc.getName() + " != null and " + jc.getName() + " != ''\">\n");
            } else {
                fileLines.add("\t\t\t<if test=\"" + jc.getName() + " != null\">\n");
            }
            fileLines.add("\t\t\t\t" + dc.getName() + " = #{" + jc.getName() + "},\n");
            fileLines.add("\t\t\t</if>\n");
        }
        fileLines.add("\t\t</set>\n");
        fileLines.add("\t\twhere id = #{id}\n");
        fileLines.add("\t</update>\n\n");

        // delete
        fileLines.add("\t<delete id=\"deleteByPrimaryKey\">\n");
        fileLines.add("\t\tdelete from " + tableName + " where id = #{id}\n");
        fileLines.add("\t</delete>\n\n");

        // delete batch
        fileLines.add("\t<delete id=\"deleteBatchByPrimaryKeyList\" parameterType=\"java.util.List\">\n");
        fileLines.add("\t\tdelete from " + tableName + " where id = #{id}\n");
        fileLines.add("\t\twhere \n");
        fileLines.add("\t\t<if test='primaryKeys!=null and primaryKeys.size!=0'> \n");
        fileLines.add("\t\t\t\t 'id' =#{id}\" \n");
        fileLines.add("\t\t\t\t in \" \n");
        fileLines.add("\t\t\t\t <foreach collection='primaryKeys' item='primaryKey'   index='index' open='(' close=')' separator=','> \" \n");
        fileLines.add("\t\t\t\t#{primaryKey}\n");
        fileLines.add("\t\t\t\t</foreach> \n\n");
        fileLines.add("\t\t</if> \n");
        fileLines.add("\t</delete>\n");
        fileLines.add("</mapper>");
        return fileLines;
    }

    public static void outputFile(String fileName, List<String> fileLines) throws IOException {
        File file = new File(fileName);
        if (!file.getParentFile().exists()) {
            file.getParentFile().mkdirs();
        }
        if (!file.exists()) {
            file.createNewFile();
        }
        Writer writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file), "UTF-8"));
        for (String line : fileLines) {
            writer.write(line);
        }
        writer.flush();
        writer.close();
    }
}

class DbColumn {

    private String name;

    private String type;
    private String remark;

    public DbColumn(String name, String type, String remark) {
        this.name = name;
        this.type = type;
        this.remark = remark;
    }

    public String getRemark() {
        return remark;
    }

    public void setRemark(String remark) {
        this.remark = remark;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getType() {
        return type;
    }

    public void setType(String type) {
        this.type = type;
    }

}

class JavaColumn {

    private String name;

    private String type;

    private String remark;

    public JavaColumn(String name, String type, String remark) {
        String[] words = name.split("_");
        for (int i = 0; i < words.length; i++) {
            if (i == 0) {
                name = words[i];
            } else {
                name += words[i].substring(0, 1).toUpperCase() + words[i].substring(1);
            }
        }

        this.name = name;
        this.remark = remark;

        if ("INT".equalsIgnoreCase(type)) {
            this.type = "Integer";
        } else if ("INT UNSIGNED".equalsIgnoreCase(type)) {
            this.type = "Integer";
        } else if ("BIGINT".equalsIgnoreCase(type)) {
            this.type = "Long";
        } else if ("SMALLINT".equalsIgnoreCase(type)) {
            this.type = "short";
        } else if ("FLOAT".equalsIgnoreCase(type)) {
            this.type = "float";
        } else if ("DECIMAL".equalsIgnoreCase(type)) {
            this.type = "BigDecimal";
        } else if ("VARCHAR".equalsIgnoreCase(type)) {
            this.type = "String";
        } else if (type.contains("TEXT")) {
            this.type = "String";
        } else if (type.contains("BLOB")) {
            this.type = "byte[]";
        } else if ("datetime".equalsIgnoreCase(type)) {
            this.type = "Date";
        } else if ("double".equalsIgnoreCase(type)) {
            this.type = "Double";
        } else if ("char".equalsIgnoreCase(type)) {
            this.type = "Integer";
        } else if ("text".equalsIgnoreCase(type)) {
            this.type = "String";
        } else if ("tinyint".equalsIgnoreCase(type)) {
            this.type = "Integer";
        }

    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getType() {
        return type;
    }

    public void setType(String type) {
        this.type = type;
    }

    public String getRemark() {
        return remark;
    }

    public void setRemark(String remark) {
        this.remark = remark;
    }
}
